﻿using System.Text.Json;

namespace OpenAIProxy;

public interface IFileStorage
{
    Task SaveChatRecordAsync(ChatRecord record);
    Task LogInformationAsync(string message);
    Task LogErrorAsync(string message);
}

public class FileStorageService : IFileStorage
{
    private readonly string _chatDirectory;
    private readonly string _logDirectory;
    private readonly int _maxFileSizeMB;
    private readonly int _maxFilesToKeep;
    private readonly SemaphoreSlim _fileLock = new(1, 1);

    public FileStorageService(IConfiguration config)
    {
        var storageConfig = config.GetSection("FileStorage");
        _chatDirectory = storageConfig["ChatDirectory"] ?? "chat_records";
        _logDirectory = storageConfig["LogDirectory"] ?? "logs";
        _maxFileSizeMB = storageConfig.GetValue("MaxChatFileSizeMB", 100);
        _maxFilesToKeep = storageConfig.GetValue("MaxFilesToKeep", 30);

        EnsureDirectory(_chatDirectory);
        EnsureDirectory(_logDirectory);
    }

    private void EnsureDirectory(string path)
    {
        if (!Directory.Exists(path))
        {
            Directory.CreateDirectory(path);
        }
    }

    private async Task WriteToTextFile(string filePath, string content)
    {
        await _fileLock.WaitAsync();
        try
        {
            await File.AppendAllTextAsync(filePath, content + Environment.NewLine);
        }
        finally
        {
            _fileLock.Release();
        }
    }

    public async Task SaveChatRecordAsync(ChatRecord record)
    {
        try
        {
            var dateStamp = DateTime.Now.ToString("yyyyMMdd");
            var chatPath = Path.Combine(_chatDirectory, $"chat_{dateStamp}.json");
            
            await EnsureFileSize(chatPath, _maxFileSizeMB * 1024 * 1024);
            await File.AppendAllTextAsync(chatPath, JsonSerializer.Serialize(record) + Environment.NewLine);
        }
        catch (Exception ex)
        {
            await LogErrorAsync($"保存聊天记录失败: {ex.Message}");
        }
        finally
        {
            _ = Task.Run(() => CleanOldFiles(_chatDirectory));
        }
    }

    private async Task EnsureFileSize(string filePath, long maxSize)
    {
        if (File.Exists(filePath))
        {
            var fileInfo = new FileInfo(filePath);
            if (fileInfo.Length > maxSize)
            {
                var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
                var newPath = Path.Combine(
                    Path.GetDirectoryName(filePath), 
                    $"{Path.GetFileNameWithoutExtension(filePath)}_{timestamp}{Path.GetExtension(filePath)}");
                
                File.Move(filePath, newPath);
            }
        }
        else
        {
            var dir = Path.GetDirectoryName(filePath);
            if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
            
            await File.WriteAllTextAsync(filePath, "");
        }
    }

    public async Task LogInformationAsync(string message)
    {
        await WriteLog("INFO", message);
    }

    public async Task LogErrorAsync(string message)
    {
        await WriteLog("ERROR", message);
    }

    private async Task WriteLog(string level, string message)
    {
        var dateStamp = DateTime.Now.ToString("yyyyMMdd");
        var logPath = Path.Combine(_logDirectory, $"proxy_{dateStamp}.log");
        
        await EnsureFileSize(logPath, (_maxFileSizeMB / 10) * 1024 * 1024);
        
        var logEntry = $"[{DateTime.Now:u}] [{level}] - {message}";
        await WriteToTextFile(logPath, logEntry);
    }

    private async Task CleanOldFiles(string directoryPath)
    {
        await _fileLock.WaitAsync();
        try
        {
            var files = new DirectoryInfo(directoryPath).GetFiles()
                .OrderByDescending(f => f.CreationTime)
                .ToList();

            if (files.Count > _maxFilesToKeep)
            {
                var filesToDelete = files.Skip(_maxFilesToKeep);
                foreach (var file in filesToDelete)
                {
                    try
                    {
                        File.Delete(file.FullName);
                    }
                    catch (Exception ex)
                    {
                        // 记录错误日志但不要中断流程
                        await WriteLog("WARN", $"删除旧文件失败: {file.Name} | {ex.Message}");
                    }
                }
            }
        }
        finally
        {
            _fileLock.Release();
        }
    }
}
